﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;

using RexToy.Xml;

namespace RexToy.UI.WinForm.Pmlx
{
    public class PmlxNode
    {
        private XAccessor _x;
        internal PmlxNode(XAccessor x, PmlxDoc doc)
        {
            _x = x;
            _doc = doc;
        }

        private PmlxDoc _doc;
        public PmlxDoc OwnerDocument
        {
            get { return _doc; }
        }

        public Type MakeType()
        {
            string ns = _doc.GetNamespaceOfPrefix(this._x.Prefix);
            if (!ns.StartsWith(ClrClassPath.CLR_SCHEME))
                ExceptionHelper.ThrowInvalidSchema(ns);

            if (ns == PmlxConstant.STD_4_0)
            {
                string typeName = string.Format("{0}.{1}", typeof(Control).Namespace, _x.LocalName);
                Type type = typeof(Control).Assembly.GetType(typeName);
                return type;
            }
            if (ns == PmlxConstant.STD_4_0_C)
            {
                string typeName = string.Format("{0}.{1}", typeof(System.Windows.Forms.DataVisualization.Charting.Chart).Namespace, _x.LocalName);
                Type type = typeof(System.Windows.Forms.DataVisualization.Charting.Chart).Assembly.GetType(typeName);
                return type;
            }
            if (ns == PmlxConstant.STD_X_4_0)
            {
                //Note:Reference to type which depend on this module.
                string typeName = string.Format("{0}.{1}", PmlxConstant.EXT_CONTROL_NAMESPACE, _x.LocalName);
                Type type = this.GetType().Assembly.GetType(typeName);
                return type;
            }
            ClrClassPath p = ns.RemoveBegin(ClrClassPath.CLR_SCHEME);
            return p.MakeType(this._x.LocalName);
        }

        public bool Renderable
        {
            get
            {
                if (this._doc.GetNamespaceOfPrefix(_x.Prefix) == PmlxConstant.STD_X_4_0)
                {
                    if (_x.LocalName == PmlxConstant.STYLE_SHEET
                        || _x.LocalName == PmlxConstant.STATIC_RESOURCE
                        || _x.LocalName == PmlxConstant.VIEW_MODEL)
                        return false;
                }
                return true;
            }
        }

        public IEnumerable<PmlxNode> ChildNodes
        {
            get
            {
                foreach (XAccessor x in _x.Children)
                {
                    if (x.IsComment)
                        continue;

                    yield return new PmlxNode(x, this._doc);
                }
            }
        }

        public IEnumerable<PmlxNode> Attributes
        {
            get
            {
                foreach (XAccessor x in _x.Attributes)
                {
                    yield return new PmlxNode(x, _doc);
                }
            }
        }

        public string Prefix
        {
            get { return _x.Prefix; }
        }

        public string LocalName
        {
            get { return _x.LocalName; }
        }

        public string Value
        {
            get { return _x.GetStringValue(); }
        }

        public bool IsTemplate
        {
            get { return _x.LocalName == PmlxConstant.TEMPLATE && string.IsNullOrEmpty(_x.Prefix); }
        }

        public PmlxNode NavigateToSingle(string xpath)
        {
            var r = _x.NavigateToSingle(xpath);
            return new PmlxNode(r, _doc);
        }

        public PmlxNode NavigateToSingleOrNull(string xpath)
        {
            var r = _x.NavigateToSingleOrNull(xpath);
            return (r == null) ? null : new PmlxNode(r, _doc);
        }

        public XAccessor Accessor
        {
            get { return _x; }
        }
    }
}
